/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hop.core;

import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;

/**
 * Universal image storage for SWT processing. It contains SVG or bitmap image depends on file and
 * settings.
 */
public abstract class SwtUniversalImage {

  private Map<String, Image> cache = new TreeMap<>();

  @Deprecated(since = "2.0")
  protected abstract Image renderSimple(Device device);

  protected abstract Image renderSimple(Device device, int width, int height);

  protected abstract Image renderRotated(Device device, int width, int height, double angleRadians);

  public synchronized void dispose() {
    if (cache == null) {
      return;
    }

    for (Image img : cache.values()) {
      if (!img.isDisposed()) {
        img.dispose();
      }
    }
    cache = null;
  }

  private void checkDisposed() {
    if (cache == null) {
      throw new RuntimeException("Already disposed");
    }
  }

  /**
   * @deprecated Use getAsBitmapForSize() instead.
   */
  @Deprecated(since = "2.0")
  public synchronized Image getAsBitmap(Device device) {
    checkDisposed();

    Image result = cache.get("");

    if (result == null) {
      result = renderSimple(device);
      cache.put("", result);
    }
    return result;
  }

  /** Method getAsBitmapForSize(..., angle) can't be called, because it returns bigger picture. */
  public synchronized Image getAsBitmapForSize(Device device, int width, int height) {
    checkDisposed();

    String key = width + "x" + height;
    Image result = cache.get(key);
    if (result == null) {
      result = renderSimple(device, width, height);
      cache.put(key, result);
    }
    return result;
  }

  /** Draw rotated image on double canvas size. It required against lost corners on rotate. */
  public synchronized Image getAsBitmapForSize(
      Device device, int width, int height, double angleRadians) {
    checkDisposed();

    int angleDegree = (int) Math.round(Math.toDegrees(angleRadians));
    while (angleDegree < 0) {
      angleDegree += 360;
    }
    angleDegree %= 360;
    angleRadians = Math.toRadians(angleDegree);

    String key = width + "x" + height + "/" + angleDegree;
    Image result = cache.get(key);
    if (result == null) {
      result = renderRotated(device, width, height, angleRadians);
      cache.put(key, result);
    }

    return result;
  }

  /** Converts BufferedImage to SWT/Image with alpha channel. */
  protected Image swing2swt(Device device, BufferedImage img) {
    PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
    ImageData data = new ImageData(img.getWidth(), img.getHeight(), 32, palette);
    for (int y = 0; y < data.height; y++) {
      for (int x = 0; x < data.width; x++) {
        int rgba = img.getRGB(x, y);
        int rgb = palette.getPixel(new RGB((rgba >> 16) & 0xFF, (rgba >> 8) & 0xFF, rgba & 0xFF));
        int a = (rgba >> 24) & 0xFF;
        data.setPixel(x, y, rgb);
        data.setAlpha(x, y, a);
      }
    }
    return new Image(device, data);
  }
}
